home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65 / src / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-20  |  22.2 KB  |  1,085 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. char copyright[] =
  23. "@(#) Copyright (c) 1988 Regents of the University of California.\n\
  24.  All rights reserved.\n";
  25. #endif /* not lint */
  26.  
  27. #ifndef lint
  28. static char sccsid[] = "@(#)main.c    5.31 (Berkeley) 7/20/90";
  29. #endif /* not lint */
  30.  
  31. #define    _DEFINE
  32.  
  33. #include <sys/param.h>
  34. #include <sys/file.h>
  35. #include <signal.h>
  36. #include <sgtty.h>
  37. #include "sendmail.h"
  38. #include <arpa/nameser.h>
  39. #include <resolv.h>
  40.  
  41. # ifdef lint
  42. char    edata, end;
  43. # endif lint
  44.  
  45. /*
  46. **  SENDMAIL -- Post mail to a set of destinations.
  47. **
  48. **    This is the basic mail router.  All user mail programs should
  49. **    call this routine to actually deliver mail.  Sendmail in
  50. **    turn calls a bunch of mail servers that do the real work of
  51. **    delivering the mail.
  52. **
  53. **    Sendmail is driven by tables read in from /usr/lib/sendmail.cf
  54. **    (read by readcf.c).  Some more static configuration info,
  55. **    including some code that you may want to tailor for your
  56. **    installation, is in conf.c.  You may also want to touch
  57. **    daemon.c (if you have some other IPC mechanism), acct.c
  58. **    (to change your accounting), names.c (to adjust the name
  59. **    server mechanism).
  60. **
  61. **    Usage:
  62. **        /usr/lib/sendmail [flags] addr ...
  63. **
  64. **        See the associated documentation for details.
  65. **
  66. **    Author:
  67. **        Eric Allman, UCB/INGRES (until 10/81)
  68. **                 Britton-Lee, Inc., purveyors of fine
  69. **                database computers (from 11/81)
  70. **        The support of the INGRES Project and Britton-Lee is
  71. **            gratefully acknowledged.  Britton-Lee in
  72. **            particular had absolutely nothing to gain from
  73. **            my involvement in this project.
  74. */
  75.  
  76.  
  77. int        NextMailer;    /* "free" index into Mailer struct */
  78. char        *FullName;    /* sender's full name */
  79. ENVELOPE    BlankEnvelope;    /* a "blank" envelope */
  80. ENVELOPE    MainEnvelope;    /* the envelope around the basic letter */
  81. ADDRESS        NullAddress =    /* a null address */
  82.         { "", "", NULL, "" };
  83.  
  84. /*
  85. **  Pointers for setproctitle.
  86. **    This allows "ps" listings to give more useful information.
  87. **    These must be kept out of BSS for frozen configuration files
  88. **        to work.
  89. */
  90.  
  91. # ifdef SETPROCTITLE
  92. char        **Argv = NULL;        /* pointer to argument vector */
  93. char        *LastArgv = NULL;    /* end of argv */
  94. # endif SETPROCTITLE
  95.  
  96. #ifdef DAEMON
  97. #ifndef SMTP
  98. ERROR %%%%   Cannot have daemon mode without SMTP   %%%% ERROR
  99. #endif SMTP
  100. #endif DAEMON
  101.  
  102. main(argc, argv, envp)
  103.     int argc;
  104.     char **argv;
  105.     char **envp;
  106. {
  107.     register char *p;
  108.     char **av;
  109.     extern int finis();
  110.     extern char Version[];
  111.     char *from;
  112.     typedef int (*fnptr)();
  113.     STAB *st;
  114.     register int i;
  115.     bool readconfig = TRUE;
  116.     bool queuemode = FALSE;        /* process queue requests */
  117.     bool nothaw;
  118.     static bool reenter = FALSE;
  119.     char jbuf[30];            /* holds MyHostName */
  120.     extern bool safefile();
  121.     extern time_t convtime();
  122.     extern putheader(), putbody();
  123.     extern ENVELOPE *newenvelope();
  124.     extern intsig();
  125.     extern char **myhostname();
  126.     extern char *arpadate();
  127.     extern char **environ;
  128.  
  129.     /*
  130.     **  Check to see if we reentered.
  131.     **    This would normally happen if e_putheader or e_putbody
  132.     **    were NULL when invoked.
  133.     */
  134.  
  135.     if (reenter)
  136.     {
  137.         syserr("main: reentered!");
  138.         abort();
  139.     }
  140.     reenter = TRUE;
  141.  
  142.     /* Enforce use of local time */
  143.     unsetenv("TZ");
  144.  
  145.     /*
  146.     **  Be sure we have enough file descriptors.
  147.     **    But also be sure that 0, 1, & 2 are open.
  148.     */
  149.  
  150.     i = open("/dev/null", O_RDWR);
  151.     while (i >= 0 && i < 2)
  152.         i = dup(i);
  153.     for (i = getdtablesize(); i > 2; --i)
  154.         (void) close(i);
  155.     errno = 0;
  156.  
  157. #ifdef LOG_MAIL
  158.     openlog("sendmail", LOG_PID, LOG_MAIL);
  159. #else 
  160.     openlog("sendmail", LOG_PID);
  161. #endif 
  162.  
  163.     /*
  164.     **  Set default values for variables.
  165.     **    These cannot be in initialized data space.
  166.     */
  167.  
  168.     setdefaults();
  169.  
  170.     /* set up the blank envelope */
  171.     BlankEnvelope.e_puthdr = putheader;
  172.     BlankEnvelope.e_putbody = putbody;
  173.     BlankEnvelope.e_xfp = NULL;
  174.     STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
  175.     CurEnv = &BlankEnvelope;
  176.     STRUCTCOPY(NullAddress, MainEnvelope.e_from);
  177.  
  178.     /*
  179.     **  Do a quick prescan of the argument list.
  180.     **    We do this to find out if we can potentially thaw the
  181.     **    configuration file.  If not, we do the thaw now so that
  182.     **    the argument processing applies to this run rather than
  183.     **    to the run that froze the configuration.
  184.     */
  185.  
  186.     argv[argc] = NULL;
  187.     av = argv;
  188.     nothaw = FALSE;
  189.     while ((p = *++av) != NULL)
  190.     {
  191.         if (strncmp(p, "-C", 2) == 0)
  192.         {
  193.             ConfFile = &p[2];
  194.             if (ConfFile[0] == '\0')
  195.                 ConfFile = "sendmail.cf";
  196.             (void) setgid(getrgid());
  197.             (void) setuid(getruid());
  198.             nothaw = TRUE;
  199.         }
  200.         else if (strncmp(p, "-bz", 3) == 0)
  201.             nothaw = TRUE;
  202.         else if (strncmp(p, "-d", 2) == 0)
  203.         {
  204.             tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
  205.             tTflag(&p[2]);
  206.             setbuf(stdout, (char *) NULL);
  207.             printf("Version %s\n", Version);
  208.         }
  209.     }
  210.  
  211.     InChannel = stdin;
  212.     OutChannel = stdout;
  213.  
  214.     if (!nothaw)
  215.         readconfig = !thaw(FreezeFile);
  216.  
  217.     /* reset the environment after the thaw */
  218.     for (i = 0; i < MAXUSERENVIRON && envp[i] != NULL; i++)
  219.         UserEnviron[i] = newstr(envp[i]);
  220.     UserEnviron[i] = NULL;
  221.     environ = UserEnviron;
  222.  
  223. # ifdef SETPROCTITLE
  224.     /*
  225.     **  Save start and extent of argv for setproctitle.
  226.     */
  227.  
  228.     Argv = argv;
  229.     if (i > 0)
  230.         LastArgv = envp[i - 1] + strlen(envp[i - 1]);
  231.     else
  232.         LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
  233. # endif SETPROCTITLE
  234.  
  235.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  236.         (void) signal(SIGINT, intsig);
  237.     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  238.         (void) signal(SIGHUP, intsig);
  239.     (void) signal(SIGTERM, intsig);
  240.     (void) signal(SIGPIPE, SIG_IGN);
  241.     OldUmask = umask(0);
  242.     OpMode = MD_DELIVER;
  243.     MotherPid = getpid();
  244.     FullName = getenv("NAME");
  245.  
  246.     errno = 0;
  247.     from = NULL;
  248.  
  249.     if (readconfig)
  250.     {
  251.         /* initialize some macros, etc. */
  252.         initmacros();
  253.  
  254.         /* hostname */
  255.         av = myhostname(jbuf, sizeof jbuf);
  256.         if (jbuf[0] != '\0')
  257.         {
  258.             if (tTd(0, 4))
  259.                 printf("canonical name: %s\n", jbuf);
  260.             p = newstr(jbuf);
  261.             define('w', p, CurEnv);
  262.             setclass('w', p);
  263.         }
  264.         while (av != NULL && *av != NULL)
  265.         {
  266.             if (tTd(0, 4))
  267.                 printf("\ta.k.a.: %s\n", *av);
  268.             setclass('w', *av++);
  269.         }
  270.  
  271.         /* version */
  272.         define('v', Version, CurEnv);
  273.     }
  274.  
  275.     /* current time */
  276.     define('b', arpadate((char *) NULL), CurEnv);
  277.  
  278.     /*
  279.     ** Crack argv.
  280.     */
  281.  
  282.     av = argv;
  283.     p = rindex(*av, '/');
  284.     if (p++ == NULL)
  285.         p = *av;
  286.     if (strcmp(p, "newaliases") == 0)
  287.         OpMode = MD_INITALIAS;
  288.     else if (strcmp(p, "mailq") == 0)
  289.         OpMode = MD_PRINT;
  290.     else if (strcmp(p, "smtpd") == 0)
  291.         OpMode = MD_DAEMON;
  292.     while ((p = *++av) != NULL && p[0] == '-')
  293.     {
  294.         switch (p[1])
  295.         {
  296.           case 'b':    /* operations mode */
  297.             switch (p[2])
  298.             {
  299.               case MD_DAEMON:
  300. # ifdef DAEMON
  301.                 if (getuid() != 0) {
  302.                     usrerr("Permission denied");
  303.                     exit (EX_USAGE);
  304.                 }
  305.                 (void) unsetenv("HOSTALIASES");
  306. # else
  307.                 usrerr("Daemon mode not implemented");
  308.                 ExitStat = EX_USAGE;
  309.                 break;
  310. # endif DAEMON
  311.               case MD_SMTP:
  312. # ifndef SMTP
  313.                 usrerr("I don't speak SMTP");
  314.                 ExitStat = EX_USAGE;
  315.                 break;
  316. # endif SMTP
  317.               case MD_ARPAFTP:
  318.               case MD_DELIVER:
  319.               case MD_VERIFY:
  320.               case MD_TEST:
  321.               case MD_INITALIAS:
  322.               case MD_PRINT:
  323.               case MD_FREEZE:
  324.                 OpMode = p[2];
  325.                 break;
  326.  
  327.               default:
  328.                 usrerr("Invalid operation mode %c", p[2]);
  329.                 ExitStat = EX_USAGE;
  330.                 break;
  331.             }
  332.             break;
  333.  
  334.           case 'C':    /* select configuration file (already done) */
  335.             break;
  336.  
  337.           case 'd':    /* debugging -- redo in case frozen */
  338.             tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
  339.             tTflag(&p[2]);
  340.             setbuf(stdout, (char *) NULL);
  341. #ifdef NAMED_BIND
  342.             _res.options |= RES_DEBUG;
  343. #endif
  344.             break;
  345.  
  346.           case 'f':    /* from address */
  347.           case 'r':    /* obsolete -f flag */
  348.             p += 2;
  349.             if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
  350.             {
  351.                 p = *++av;
  352.                 if (p == NULL || *p == '-')
  353.                 {
  354.                     usrerr("No \"from\" person");
  355.                     ExitStat = EX_USAGE;
  356.                     av--;
  357.                     break;
  358.                 }
  359.             }
  360.             if (from != NULL)
  361.             {
  362.                 usrerr("More than one \"from\" person");
  363.                 ExitStat = EX_USAGE;
  364.                 break;
  365.             }
  366.             from = newstr(p);
  367.             break;
  368.  
  369.           case 'F':    /* set full name */
  370.             p += 2;
  371.             if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
  372.             {
  373.                 usrerr("Bad -F flag");
  374.                 ExitStat = EX_USAGE;
  375.                 av--;
  376.                 break;
  377.             }
  378.             FullName = newstr(p);
  379.             break;
  380.  
  381.           case 'h':    /* hop count */
  382.             p += 2;
  383.             if (*p == '\0' && ((p = *++av) == NULL || !isdigit(*p)))
  384.             {
  385.                 usrerr("Bad hop count (%s)", p);
  386.                 ExitStat = EX_USAGE;
  387.                 av--;
  388.                 break;
  389.             }
  390.             CurEnv->e_hopcount = atoi(p);
  391.             break;
  392.         
  393.           case 'n':    /* don't alias */
  394.             NoAlias = TRUE;
  395.             break;
  396.  
  397.           case 'o':    /* set option */
  398.             setoption(p[2], &p[3], FALSE, TRUE);
  399.             break;
  400.  
  401.           case 'q':    /* run queue files at intervals */
  402. # ifdef QUEUE
  403.             if (getuid() != 0) {
  404.                 usrerr("Permission denied");
  405.                 exit (EX_USAGE);
  406.             }
  407.             (void) unsetenv("HOSTALIASES");
  408.             queuemode = TRUE;
  409.             QueueIntvl = convtime(&p[2]);
  410. # else QUEUE
  411.             usrerr("I don't know about queues");
  412.             ExitStat = EX_USAGE;
  413. # endif QUEUE
  414.             break;
  415.  
  416.           case 't':    /* read recipients from message */
  417.             GrabTo = TRUE;
  418.             break;
  419.  
  420.             /* compatibility flags */
  421.           case 'c':    /* connect to non-local mailers */
  422.           case 'e':    /* error message disposition */
  423.           case 'i':    /* don't let dot stop me */
  424.           case 'm':    /* send to me too */
  425.           case 'T':    /* set timeout interval */
  426.           case 'v':    /* give blow-by-blow description */
  427.             setoption(p[1], &p[2], FALSE, TRUE);
  428.             break;
  429.  
  430.           case 's':    /* save From lines in headers */
  431.             setoption('f', &p[2], FALSE, TRUE);
  432.             break;
  433.  
  434. # ifdef DBM
  435.           case 'I':    /* initialize alias DBM file */
  436.             OpMode = MD_INITALIAS;
  437.             break;
  438. # endif DBM
  439.         }
  440.     }
  441.  
  442.     /*
  443.     **  Do basic initialization.
  444.     **    Read system control file.
  445.     **    Extract special fields for local use.
  446.     */
  447.  
  448.     if (OpMode == MD_FREEZE || readconfig)
  449.         readcf(ConfFile);
  450.  
  451.     switch (OpMode)
  452.     {
  453.       case MD_FREEZE:
  454.         /* this is critical to avoid forgeries of the frozen config */
  455.         (void) setgid(getgid());
  456.         (void) setuid(getuid());
  457.  
  458.         /* freeze the configuration */
  459.         freeze(FreezeFile);
  460.         exit(EX_OK);
  461.  
  462.       case MD_INITALIAS:
  463.         Verbose = TRUE;
  464.         break;
  465.     }
  466.  
  467.     /* do heuristic mode adjustment */
  468.     if (Verbose)
  469.     {
  470.         /* turn off noconnect option */
  471.         setoption('c', "F", TRUE, FALSE);
  472.  
  473.         /* turn on interactive delivery */
  474.         setoption('d', "", TRUE, FALSE);
  475.     }
  476.  
  477.     /* our name for SMTP codes */
  478.     expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
  479.     MyHostName = jbuf;
  480.  
  481.     /* the indices of local and program mailers */
  482.     st = stab("local", ST_MAILER, ST_FIND);
  483.     if (st == NULL)
  484.         syserr("No local mailer defined");
  485.     else
  486.         LocalMailer = st->s_mailer;
  487.     st = stab("prog", ST_MAILER, ST_FIND);
  488.     if (st == NULL)
  489.         syserr("No prog mailer defined");
  490.     else
  491.         ProgMailer = st->s_mailer;
  492.  
  493.     /* operate in queue directory */
  494.     if (chdir(QueueDir) < 0)
  495.     {
  496.         syserr("cannot chdir(%s)", QueueDir);
  497.         exit(EX_SOFTWARE);
  498.     }
  499.  
  500.     /*
  501.     **  Do operation-mode-dependent initialization.
  502.     */
  503.  
  504.     switch (OpMode)
  505.     {
  506.       case MD_PRINT:
  507.         /* print the queue */
  508. #ifdef QUEUE
  509.         dropenvelope(CurEnv);
  510.         printqueue();
  511.         exit(EX_OK);
  512. #else QUEUE
  513.         usrerr("No queue to print");
  514.         finis();
  515. #endif QUEUE
  516.  
  517.       case MD_INITALIAS:
  518.         /* initialize alias database */
  519.         initaliases(AliasFile, TRUE);
  520.         exit(EX_OK);
  521.  
  522.       case MD_DAEMON:
  523.         /* don't open alias database -- done in srvrsmtp */
  524.         break;
  525.  
  526.       default:
  527.         /* open the alias database */
  528.         initaliases(AliasFile, FALSE);
  529.         break;
  530.     }
  531.  
  532.     if (tTd(0, 15))
  533.     {
  534.         /* print configuration table (or at least part of it) */
  535.         printrules();
  536.         for (i = 0; i < MAXMAILERS; i++)
  537.         {
  538.             register struct mailer *m = Mailer[i];
  539.             int j;
  540.  
  541.             if (m == NULL)
  542.                 continue;
  543.             printf("mailer %d (%s): P=%s S=%d R=%d M=%ld F=", i, m->m_name,
  544.                 m->m_mailer, m->m_s_rwset, m->m_r_rwset,
  545.                 m->m_maxsize);
  546.             for (j = '\0'; j <= '\177'; j++)
  547.                 if (bitnset(j, m->m_flags))
  548.                     (void) putchar(j);
  549.             printf(" E=");
  550.             xputs(m->m_eol);
  551.             printf("\n");
  552.         }
  553.     }
  554.  
  555.     /*
  556.     **  Switch to the main envelope.
  557.     */
  558.  
  559.     CurEnv = newenvelope(&MainEnvelope);
  560.     MainEnvelope.e_flags = BlankEnvelope.e_flags;
  561.  
  562.     /*
  563.     **  If test mode, read addresses from stdin and process.
  564.     */
  565.  
  566.     if (OpMode == MD_TEST)
  567.     {
  568.         char buf[MAXLINE];
  569.  
  570.         printf("ADDRESS TEST MODE\nEnter <ruleset> <address>\n");
  571.         for (;;)
  572.         {
  573.             register char **pvp;
  574.             char *q;
  575.             extern char *DelimChar;
  576.  
  577.             printf("> ");
  578.             (void) fflush(stdout);
  579.             if (fgets(buf, sizeof buf, stdin) == NULL)
  580.                 finis();
  581.             for (p = buf; isspace(*p); p++)
  582.                 continue;
  583.             q = p;
  584.             while (*p != '\0' && !isspace(*p))
  585.                 p++;
  586.             if (*p == '\0')
  587.                 continue;
  588.             *p = '\0';
  589.             do
  590.             {
  591.                 extern char **prescan();
  592.                 char pvpbuf[PSBUFSIZE];
  593.  
  594.                 pvp = prescan(++p, ',', pvpbuf);
  595.                 if (pvp == NULL)
  596.                     continue;
  597.                 rewrite(pvp, 3);
  598.                 p = q;
  599.                 while (*p != '\0')
  600.                 {
  601.                     rewrite(pvp, atoi(p));
  602.                     while (*p != '\0' && *p++ != ',')
  603.                         continue;
  604.                 }
  605.             } while (*(p = DelimChar) != '\0');
  606.         }
  607.     }
  608.  
  609. # ifdef QUEUE
  610.     /*
  611.     **  If collecting stuff from the queue, go start doing that.
  612.     */
  613.  
  614.     if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
  615.     {
  616.         runqueue(FALSE);
  617.         finis();
  618.     }
  619. # endif QUEUE
  620.  
  621.     /*
  622.     **  If a daemon, wait for a request.
  623.     **    getrequests will always return in a child.
  624.     **    If we should also be processing the queue, start
  625.     **        doing it in background.
  626.     **    We check for any errors that might have happened
  627.     **        during startup.
  628.     */
  629.  
  630.     if (OpMode == MD_DAEMON || QueueIntvl != 0)
  631.     {
  632.         if (!tTd(0, 1))
  633.         {
  634.             /* put us in background */
  635.             i = fork();
  636.             if (i < 0)
  637.                 syserr("daemon: cannot fork");
  638.             if (i != 0)
  639.                 exit(0);
  640.  
  641.             /* get our pid right */
  642.             MotherPid = getpid();
  643.  
  644.             /* disconnect from our controlling tty */
  645.             disconnect(TRUE);
  646.         }
  647.  
  648. # ifdef QUEUE
  649.         if (queuemode)
  650.         {
  651.             runqueue(TRUE);
  652.             if (OpMode != MD_DAEMON)
  653.                 for (;;)
  654.                     pause();
  655.         }
  656. # endif QUEUE
  657.         dropenvelope(CurEnv);
  658.  
  659. #ifdef DAEMON
  660.         getrequests();
  661.  
  662.         /* at this point we are in a child: reset state */
  663.         OpMode = MD_SMTP;
  664.         (void) newenvelope(CurEnv);
  665.         openxscript(CurEnv);
  666. #endif DAEMON
  667.     }
  668.     
  669. # ifdef SMTP
  670.     /*
  671.     **  If running SMTP protocol, start collecting and executing
  672.     **  commands.  This will never return.
  673.     */
  674.  
  675.     if (OpMode == MD_SMTP)
  676.         smtp();
  677. # endif SMTP
  678.  
  679.     /*
  680.     **  Do basic system initialization and set the sender
  681.     */
  682.  
  683.     initsys();
  684.     setsender(from);
  685.  
  686.     if (OpMode != MD_ARPAFTP && *av == NULL && !GrabTo)
  687.     {
  688.         usrerr("Recipient names must be specified");
  689.  
  690.         /* collect body for UUCP return */
  691.         if (OpMode != MD_VERIFY)
  692.             collect(FALSE);
  693.         finis();
  694.     }
  695.     if (OpMode == MD_VERIFY)
  696.         SendMode = SM_VERIFY;
  697.  
  698.     /*
  699.     **  Scan argv and deliver the message to everyone.
  700.     */
  701.  
  702.     sendtoargv(av);
  703.  
  704.     /* if we have had errors sofar, arrange a meaningful exit stat */
  705.     if (Errors > 0 && ExitStat == EX_OK)
  706.         ExitStat = EX_USAGE;
  707.  
  708.     /*
  709.     **  Read the input mail.
  710.     */
  711.  
  712.     CurEnv->e_to = NULL;
  713.     if (OpMode != MD_VERIFY || GrabTo)
  714.         collect(FALSE);
  715.     errno = 0;
  716.  
  717.     /* collect statistics */
  718.     if (OpMode != MD_VERIFY)
  719.         markstats(CurEnv, (ADDRESS *) NULL);
  720.  
  721.     if (tTd(1, 1))
  722.         printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
  723.  
  724.     /*
  725.     **  Actually send everything.
  726.     **    If verifying, just ack.
  727.     */
  728.  
  729.     CurEnv->e_from.q_flags |= QDONTSEND;
  730.     CurEnv->e_to = NULL;
  731.     sendall(CurEnv, SM_DEFAULT);
  732.  
  733.     /*
  734.     ** All done.
  735.     */
  736.  
  737.     finis();
  738. }
  739. /*
  740. **  FINIS -- Clean up and exit.
  741. **
  742. **    Parameters:
  743. **        none
  744. **
  745. **    Returns:
  746. **        never
  747. **
  748. **    Side Effects:
  749. **        exits sendmail
  750. */
  751.  
  752. finis()
  753. {
  754.     if (tTd(2, 1))
  755.         printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags);
  756.  
  757.     /* clean up temp files */
  758.     CurEnv->e_to = NULL;
  759.     dropenvelope(CurEnv);
  760.  
  761.     /* post statistics */
  762.     poststats(StatFile);
  763.  
  764.     /* and exit */
  765. # ifdef LOG
  766.     if (LogLevel > 11)
  767.         syslog(LOG_DEBUG, "finis, pid=%d", getpid());
  768. # endif LOG
  769.     if (ExitStat == EX_TEMPFAIL)
  770.         ExitStat = EX_OK;
  771.     exit(ExitStat);
  772. }
  773. /*
  774. **  INTSIG -- clean up on interrupt
  775. **
  776. **    This just arranges to exit.  It pessimises in that it
  777. **    may resend a message.
  778. **
  779. **    Parameters:
  780. **        none.
  781. **
  782. **    Returns:
  783. **        none.
  784. **
  785. **    Side Effects:
  786. **        Unlocks the current job.
  787. */
  788.  
  789. intsig()
  790. {
  791.     FileName = NULL;
  792.     unlockqueue(CurEnv);
  793.     exit(EX_OK);
  794. }
  795. /*
  796. **  INITMACROS -- initialize the macro system
  797. **
  798. **    This just involves defining some macros that are actually
  799. **    used internally as metasymbols to be themselves.
  800. **
  801. **    Parameters:
  802. **        none.
  803. **
  804. **    Returns:
  805. **        none.
  806. **
  807. **    Side Effects:
  808. **        initializes several macros to be themselves.
  809. */
  810.  
  811. struct metamac
  812. {
  813.     char    metaname;
  814.     char    metaval;
  815. };
  816.  
  817. struct metamac    MetaMacros[] =
  818. {
  819.     /* LHS pattern matching characters */
  820.     '*', MATCHZANY,    '+', MATCHANY,    '-', MATCHONE,    '=', MATCHCLASS,
  821.     '~', MATCHNCLASS,
  822.  
  823.     /* these are RHS metasymbols */
  824.     '#', CANONNET,    '@', CANONHOST,    ':', CANONUSER,    '>', CALLSUBR,
  825.  
  826.     /* the conditional operations */
  827.     '?', CONDIF,    '|', CONDELSE,    '.', CONDFI,
  828.  
  829.     /* and finally the hostname lookup characters */
  830.     '[', HOSTBEGIN,    ']', HOSTEND,
  831.  
  832.     '\0'
  833. };
  834.  
  835. initmacros()
  836. {
  837.     register struct metamac *m;
  838.     char buf[5];
  839.     register int c;
  840.  
  841.     for (m = MetaMacros; m->metaname != '\0'; m++)
  842.     {
  843.         buf[0] = m->metaval;
  844.         buf[1] = '\0';
  845.         define(m->metaname, newstr(buf), CurEnv);
  846.     }
  847.     buf[0] = MATCHREPL;
  848.     buf[2] = '\0';
  849.     for (c = '0'; c <= '9'; c++)
  850.     {
  851.         buf[1] = c;
  852.         define(c, newstr(buf), CurEnv);
  853.     }
  854. }
  855. /*
  856. **  FREEZE -- freeze BSS & allocated memory
  857. **
  858. **    This will be used to efficiently load the configuration file.
  859. **
  860. **    Parameters:
  861. **        freezefile -- the name of the file to freeze to.
  862. **
  863. **    Returns:
  864. **        none.
  865. **
  866. **    Side Effects:
  867. **        Writes BSS and malloc'ed memory to freezefile
  868. */
  869.  
  870. union frz
  871. {
  872.     char        frzpad[BUFSIZ];    /* insure we are on a BUFSIZ boundary */
  873.     struct
  874.     {
  875.         time_t    frzstamp;    /* timestamp on this freeze */
  876.         char    *frzbrk;    /* the current break */
  877.         char    *frzedata;    /* address of edata */
  878.         char    *frzend;    /* address of end */
  879.         char    frzver[252];    /* sendmail version */
  880.     } frzinfo;
  881. };
  882.  
  883. freeze(freezefile)
  884.     char *freezefile;
  885. {
  886.     int f;
  887.     union frz fhdr;
  888.     extern char edata, end;
  889.     extern char *sbrk();
  890.     extern char Version[];
  891.  
  892.     if (freezefile == NULL)
  893.         return;
  894.  
  895.     /* try to open the freeze file */
  896.     f = creat(freezefile, FileMode);
  897.     if (f < 0)
  898.     {
  899.         syserr("Cannot freeze %s", freezefile);
  900.         errno = 0;
  901.         return;
  902.     }
  903.  
  904.     /* build the freeze header */
  905.     fhdr.frzinfo.frzstamp = curtime();
  906.     fhdr.frzinfo.frzbrk = sbrk(0);
  907.     fhdr.frzinfo.frzedata = &edata;
  908.     fhdr.frzinfo.frzend = &end;
  909.     (void) strcpy(fhdr.frzinfo.frzver, Version);
  910.  
  911.     /* write out the freeze header */
  912.     if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr ||
  913.         write(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) !=
  914.                     (int) (fhdr.frzinfo.frzbrk - &edata))
  915.     {
  916.         syserr("Cannot freeze %s", freezefile);
  917.     }
  918.  
  919.     /* fine, clean up */
  920.     (void) close(f);
  921. }
  922. /*
  923. **  THAW -- read in the frozen configuration file.
  924. **
  925. **    Parameters:
  926. **        freezefile -- the name of the file to thaw from.
  927. **
  928. **    Returns:
  929. **        TRUE if it successfully read the freeze file.
  930. **        FALSE otherwise.
  931. **
  932. **    Side Effects:
  933. **        reads freezefile in to BSS area.
  934. */
  935.  
  936. thaw(freezefile)
  937.     char *freezefile;
  938. {
  939.     int f;
  940.     union frz fhdr;
  941.     extern char edata, end;
  942.     extern char Version[];
  943.     extern caddr_t brk();
  944.  
  945.     if (freezefile == NULL)
  946.         return (FALSE);
  947.  
  948.     /* open the freeze file */
  949.     f = open(freezefile, 0);
  950.     if (f < 0)
  951.     {
  952.         syslog(LOG_WARNING, "Cannot open frozen config file %s: %m",
  953.             freezefile);
  954.         errno = 0;
  955.         return (FALSE);
  956.     }
  957.  
  958.     /* read in the header */
  959.     if (read(f, (char *) &fhdr, sizeof fhdr) < sizeof fhdr)
  960.     {
  961.         syserr("Cannot read frozen config file");
  962.         (void) close(f);
  963.         return (FALSE);
  964.     }
  965.     if ( fhdr.frzinfo.frzedata != &edata ||
  966.         fhdr.frzinfo.frzend != &end ||
  967.         strcmp(fhdr.frzinfo.frzver, Version) != 0)
  968.     {
  969.         syslog(LOG_WARNING, "Wrong version of frozen config file");
  970.         (void) close(f);
  971.         return (FALSE);
  972.     }
  973.  
  974.     /* arrange to have enough space */
  975.     if (brk(fhdr.frzinfo.frzbrk) == (caddr_t) -1)
  976.     {
  977.         syserr("Cannot break to %x", fhdr.frzinfo.frzbrk);
  978.         (void) close(f);
  979.         return (FALSE);
  980.     }
  981.  
  982.     /* now read in the freeze file */
  983.     if (read(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) !=
  984.                     (int) (fhdr.frzinfo.frzbrk - &edata))
  985.     {
  986.         syserr("Cannot read frozen config file");
  987.         /* oops!  we have trashed memory..... */
  988.         (void) write(2, "Cannot read freeze file\n", 24);
  989.         _exit(EX_SOFTWARE);
  990.     }
  991.  
  992.     (void) close(f);
  993.     return (TRUE);
  994. }
  995. /*
  996. **  DISCONNECT -- remove our connection with any foreground process
  997. **
  998. **    Parameters:
  999. **        fulldrop -- if set, we should also drop the controlling
  1000. **            TTY if possible -- this should only be done when
  1001. **            setting up the daemon since otherwise UUCP can
  1002. **            leave us trying to open a dialin, and we will
  1003. **            wait for the carrier.
  1004. **
  1005. **    Returns:
  1006. **        none
  1007. **
  1008. **    Side Effects:
  1009. **        Trys to insure that we are immune to vagaries of
  1010. **        the controlling tty.
  1011. */
  1012.  
  1013. disconnect(fulldrop)
  1014.     bool fulldrop;
  1015. {
  1016.     int fd;
  1017.  
  1018.     if (tTd(52, 1))
  1019.         printf("disconnect: In %d Out %d\n", fileno(InChannel),
  1020.                         fileno(OutChannel));
  1021.     if (tTd(52, 5))
  1022.     {
  1023.         printf("don't\n");
  1024.         return;
  1025.     }
  1026.  
  1027.     /* be sure we don't get nasty signals */
  1028.     (void) signal(SIGHUP, SIG_IGN);
  1029.     (void) signal(SIGINT, SIG_IGN);
  1030.     (void) signal(SIGQUIT, SIG_IGN);
  1031.  
  1032.     /* we can't communicate with our caller, so.... */
  1033.     HoldErrs = TRUE;
  1034.     ErrorMode = EM_MAIL;
  1035.     Verbose = FALSE;
  1036.  
  1037.     /* all input from /dev/null */
  1038.     if (InChannel != stdin)
  1039.     {
  1040.         (void) fclose(InChannel);
  1041.         InChannel = stdin;
  1042.     }
  1043.     (void) freopen("/dev/null", "r", stdin);
  1044.  
  1045.     /* output to the transcript */
  1046.     if (OutChannel != stdout)
  1047.     {
  1048.         (void) fclose(OutChannel);
  1049.         OutChannel = stdout;
  1050.     }
  1051.     if (CurEnv->e_xfp == NULL)
  1052.         CurEnv->e_xfp = fopen("/dev/null", "w");
  1053.     (void) fflush(stdout);
  1054.     (void) close(1);
  1055.     (void) close(2);
  1056.     while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0)
  1057.         continue;
  1058.  
  1059.     /* drop our controlling TTY completely if possible */
  1060.     if (fulldrop)
  1061.     {
  1062. #if BSD > 43
  1063.         daemon(1, 1);
  1064. #else
  1065. #ifdef TIOCNOTTY
  1066.         fd = open("/dev/tty", 2);
  1067.         if (fd >= 0)
  1068.         {
  1069.             (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
  1070.             (void) close(fd);
  1071.         }
  1072.         (void) setpgrp(0, 0);
  1073. #endif /* TIOCNOTTY */
  1074. #endif /* BSD */
  1075.         errno = 0;
  1076.     }
  1077.  
  1078. # ifdef LOG
  1079.     if (LogLevel > 11)
  1080.         syslog(LOG_DEBUG, "in background, pid=%d", getpid());
  1081. # endif LOG
  1082.  
  1083.     errno = 0;
  1084. }
  1085.